//
// Created by 79816 on 2023/1/17.
//

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "mgw.h"
#include "common.h"
#include "sha256.h"
#include "CCL.h"

MGW_store mgw_store;
int reg_num=0;

REG_response mgw_reg_process(REG_request req)
{
    srand((unsigned)time(NULL));
    int r1=rand();
    int temp=0;
    unsigned char km[KEY_LENGTH_BYTES];
    unsigned char k[KEY_LENGTH_BYTES];
    unsigned char k1[KEY_LENGTH_BYTES];
    unsigned char mr[KEY_LENGTH_BYTES];
    unsigned char hash_plain[KEY_LENGTH_BYTES+4];
    unsigned char hash_result[SHA256_SIZE_BYTES];
    unsigned char f=0;
    int n=0;
    int xor_temp;
    int xor_result;

    for(int i=0;i<KEY_LENGTH_BYTES;++i)
    {
        temp=rand()%255;
        k[i] = (unsigned char)temp;
        temp=rand()%255;
        km[i] = (unsigned char)temp;
    }
    memcpy(hash_plain,k,KEY_LENGTH_BYTES);
    memcpy(hash_plain+KEY_LENGTH_BYTES,&r1,4);

    sha256(hash_plain,sizeof(hash_plain),hash_result);
    // 转换成int后再进行异或，注意内存顺序
    memcpy(&xor_temp,km,4);
    xor_result=r1^xor_temp;
    memcpy(mr,&xor_result,4);
    memcpy(mr+4,km+4,KEY_LENGTH_BYTES-4);

    REG_response response;

    memcpy(response.k1,hash_result,KEY_LENGTH_BYTES);
    response.f=f;
    response.n=0;
    memcpy(response.mr,mr,KEY_LENGTH_BYTES);

    memcpy(mgw_store.km, km, KEY_LENGTH_BYTES);
    memcpy(mgw_store.gw_material[reg_num].ID, req.ID, 2);
    memcpy(mgw_store.gw_material[reg_num].k, k, KEY_LENGTH_BYTES);
    mgw_store.gw_material[reg_num].n=n;
    reg_num++;



    return response;
}

AUTH_response mgw_auth_process(AUTH_request request)
{
    unsigned char key_xor_result[KEY_LENGTH_BYTES];
    unsigned char hash_plain[KEY_LENGTH_BYTES+INT_SIZE];
    unsigned char hash_result_1[SHA256_SIZE_BYTES];
    unsigned char hash_result_2[SHA256_SIZE_BYTES];
    unsigned char hash_result_3[SHA256_SIZE_BYTES];
    unsigned char xor_temp[INT_SIZE];
    unsigned char f1_plain[KEY_LENGTH_BYTES+CHAR_SIZE+INT_SIZE*2];
    unsigned char mgw_f1[KEY_LENGTH_BYTES];
    int r2;
    int n=-1;

    // calculate r2
    for(int m=0;m<KEY_LENGTH_BYTES;++m)
    {
        key_xor_result[m]= mgw_store.km[m] ^ request.mr[m];
    }
    memcpy(hash_plain,mgw_store.gw_material[0].k,KEY_LENGTH_BYTES);
    memcpy(hash_plain+KEY_LENGTH_BYTES, key_xor_result, INT_SIZE);
    sha256(hash_plain,sizeof(hash_plain),hash_result_1);
    sha256(hash_result_1,KEY_LENGTH_BYTES,hash_result_2);
    for(int m=0;m<INT_SIZE;++m)
    {
        xor_temp[m]=request.i[m]^hash_result_2[m];
    }
    memcpy(&r2,xor_temp,INT_SIZE);

   // printf("\nmgw_r2:%d\n",r2);

    // calculate n
    memcpy(hash_plain,hash_result_1,KEY_LENGTH_BYTES);
    memcpy(hash_plain+KEY_LENGTH_BYTES,&r2,INT_SIZE);
    sha256(hash_plain, sizeof(hash_plain),hash_result_3);
    for(int m=0;m<INT_SIZE;++m)
    {
        xor_temp[m]=request.j[m]^hash_result_3[m];
    }
    memcpy(&n,xor_temp,INT_SIZE);
   // printf("\nmgw_n:%d\n",n);

    // calculate f1*;
    memcpy(f1_plain,hash_result_2,KEY_LENGTH_BYTES);
    memcpy(f1_plain+KEY_LENGTH_BYTES,&request.f,CHAR_SIZE);
    memcpy(f1_plain+KEY_LENGTH_BYTES+CHAR_SIZE,&r2,INT_SIZE);
    memcpy(f1_plain+KEY_LENGTH_BYTES+CHAR_SIZE+INT_SIZE,&n,INT_SIZE);
    sha256(f1_plain, sizeof(f1_plain),hash_result_3);
    memcpy(mgw_f1,hash_result_3,KEY_LENGTH_BYTES);

    /*printf("mgw_f1:");
    print_hex(mgw_f1, sizeof(mgw_f1));
    printf("f1:");
    print_hex(request.f1, sizeof(request.f1));*/

    // compare f1* with f1, n* with n
    if(memcmp(mgw_f1,request.f1,KEY_LENGTH_BYTES)||n<mgw_store.gw_material[0].n)
    {
       cclPrintf("main_gateway: authentication failed!");
        exit(-1);
    }else
    {
       cclPrintf("main_gateway: f1* == f1, authentication passed!");
    }

    // add n
    mgw_store.gw_material[0].n++;

    // ---------update key---------
    unsigned char knew[KEY_LENGTH_BYTES];
    unsigned char k1new[KEY_LENGTH_BYTES];
    unsigned char kseaf[KEY_LENGTH_BYTES];
    unsigned char d1[KEY_LENGTH_BYTES];
    unsigned char f2[KEY_LENGTH_BYTES];
    unsigned char kseaf_plain[KEY_LENGTH_BYTES+INT_SIZE*2];

    // gen r3
    srand((unsigned)time(NULL));
    int r3=rand();

    // gen knew
    int temp=0;
    for(int i=0;i<KEY_LENGTH_BYTES;++i)
    {
        temp=rand()%255;
        knew[i] = (unsigned char)temp;
    }

    // calculate k1new
    memcpy(hash_plain,knew,KEY_LENGTH_BYTES);
    memcpy(hash_plain+KEY_LENGTH_BYTES,&r3,INT_SIZE);
    sha256(hash_plain, sizeof(hash_plain),hash_result_2);
    memcpy(k1new,hash_result_2,KEY_LENGTH_BYTES);

    // calculate kseaf
    int temp_n=mgw_store.gw_material[0].n+1;
    memcpy(kseaf_plain,&r2,INT_SIZE);
    memcpy(kseaf_plain+INT_SIZE,hash_result_1,KEY_LENGTH_BYTES);
    memcpy(kseaf_plain+INT_SIZE+KEY_LENGTH_BYTES,&temp_n,INT_SIZE);
    sha256(kseaf_plain, sizeof(kseaf_plain),hash_result_3);
    memcpy(kseaf,hash_result_3,KEY_LENGTH_BYTES);
    cclWrite("Ks on mgw:");
    char print_buf[KEY_LENGTH_BYTES*2+1];
    arrayToStr(kseaf, KEY_LENGTH_BYTES, print_buf);
    print_buf[KEY_LENGTH_BYTES * 2] = '\0';
    cclPrintf("%s", print_buf);

    // calculate d1
    for(int i=0;i<KEY_LENGTH_BYTES;++i)
    {
        key_xor_result[i]=k1new[i]^hash_result_1[i];
    }
    hash_xor_int(key_xor_result,r2,d1);

    // calculate f2
    sha256(kseaf, sizeof(kseaf),hash_result_3);
    memcpy(f2,hash_result_3,KEY_LENGTH_BYTES);

    // update k
    memcpy(mgw_store.gw_material[0].k, knew, KEY_LENGTH_BYTES);

    AUTH_response response;
    memcpy(response.d1,d1,KEY_LENGTH_BYTES);
    memcpy(response.f2,f2,KEY_LENGTH_BYTES);

    return response;

}

void store_mgw_material(unsigned char km[KEY_LENGTH_BYTES], unsigned char ID[2], REG_response response)
{

}